﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using CVS_log_parser;
using System.ComponentModel;

namespace CVS_log_visualiser
{
    class ListViewFiller
    {
        ListView listView;

        public ListViewFiller( ListView listView, CvsFileInfoCollection cvsFiles )
        {
            this.listView = listView;
            this.cvsFiles = cvsFiles;
            this.BackgroundDataUpdater.DoWork += new DoWorkEventHandler( BackgroundDataUpdater_DoWork );
            this.BackgroundDataUpdater.RunWorkerCompleted += new RunWorkerCompletedEventHandler( BackgroundDataUpdater_RunWorkerCompleted );
            //this.BackgroundDataUpdater.ProgressChanged += new ProgressChangedEventHandler( BackgroundDataUpdater_ProgressChanged );
        }

        BackgroundWorker BackgroundDataUpdater = new BackgroundWorker();// { WorkerReportsProgress = true };

        void FillListViewWithGroupItems( ListViewGroup group, ListViewItem[] groupItems )
        {
            this.listView.Groups.Add( group );
            this.listView.Items.AddRange( groupItems );
            group.Items.AddRange( groupItems );
        }

        void ClearListView()
        {
            this.listView.Columns.Clear();
            this.listView.Items.Clear();
        }

        private void InsertColumns( CvsFileInfo cvsFile )
        {
            cvsFile.Keys.ToList().ForEach( key => this.listView.Columns.Add( key ) );
            cvsFile.Revisions.First().Keys.ToList().ForEach( key => this.listView.Columns.Add( key ) );
        }

        static ListViewItem[] SelectAllItems( IEnumerable<CvsFileRevision> files )
        {
            return files.Select(
                            revision => new ListViewItem(
                                revision.ParentFileInfo.Keys.Select(
                                    key => revision.ParentFileInfo[key].ToString()
                                ).Concat(
                                    revision.Keys.Select( key => revision[key].ToString() )
                                ).ToArray()
                            )
                        ).ToArray();
        }

        CvsFileInfoCollection cvsFiles;

        public void UpdateData( Func<CvsFileRevision, object> selector )
        {
            //this.groupByToolStripMenuItem.Enabled = false;
            this.listView.Visible = false;

            this.BackgroundDataUpdater.RunWorkerAsync( selector );
        }

        //void BackgroundDataUpdater_ProgressChanged( object sender, ProgressChangedEventArgs e )
        //{
        //    //this.toolStripProgressBar.PerformStep();
        //}

        void BackgroundDataUpdater_RunWorkerCompleted( object sender, RunWorkerCompletedEventArgs e )
        {
            this.listView.Visible = true;
            //this.groupByToolStripMenuItem.Enabled = true;
            //this.toolStripProgressBar.ProgressBar.Value = 0;
        }

        void BackgroundDataUpdater_DoWork( object sender, DoWorkEventArgs e )
        {
            UpdateDataInBackground( e.Argument as Func<CvsFileRevision, object> );
        }


        void UpdateDataInBackground<TGroupingKey>( Func<CvsFileRevision, TGroupingKey> selector )
        {
            if ( this.cvsFiles == null || this.cvsFiles.Count() == 0 )
                return;

            if ( listView.InvokeRequired )
                listView.Invoke( new Action( ClearListView ) );
            else
                ClearListView();

            var cvsFile = this.cvsFiles.First();

            if ( listView.InvokeRequired )
                listView.Invoke( new Action<CvsFileInfo>( InsertColumns ), cvsFile );
            else
                InsertColumns( cvsFile );

            var groups = new List<ListViewGroup>();

            GroupBy( selector );
        }

        void GroupBy<TGroupingKey>( Func<CvsFileRevision, TGroupingKey> selector )
        {
            var revisions = this.cvsFiles.SelectMany( file => file.Revisions );

            if ( selector != null )
            {
                var groupMembersLookup = revisions.ToLookup( selector );
                var groupNames = revisions.GroupBy( selector ).Select( revisionGroup => revisionGroup.Key ).OrderByDescending( key => key/*, new ListViewColumnSorter<TGroupingKey>()*/ );
                var nLeft = groupNames.Count();

                //if ( this.statusStrip1.InvokeRequired )
                //    this.statusStrip1.Invoke( new Action( () => this.toolStripProgressBar.Maximum = nLeft ) );
                //else
                //    this.toolStripProgressBar.Maximum = nLeft;

                foreach ( var groupName in groupNames )
                {
                    var group = new ListViewGroup() { Header = groupName.ToString() };
                    var groupItems = SelectAllItems( groupMembersLookup[groupName] );

                    foreach ( var groupItem in groupItems )
                        if ( listView.InvokeRequired )
                            listView.Invoke( new Action<ListViewGroup, ListViewItem[]>( FillListViewWithGroupItems ), group, new ListViewItem[] { groupItem } );
                        else
                            FillListViewWithGroupItems( group, new ListViewItem[] { groupItem } );

                    //this.BackgroundDataUpdater.ReportProgress( --nLeft );
                }
            }
            else
            {
                var allitems = SelectAllItems( revisions );

                if ( this.listView.InvokeRequired )
                    this.listView.Invoke( new Action<ListViewItem[]>( this.listView.Items.AddRange ), allitems );
                else
                    this.listView.Items.AddRange( allitems );
            }
        }

    }
}
